#pragma once
#include <iostream>
#include <string>
#include <functional>
#include <memory>
#include <jsoncpp/json/json.h>
#include "Log.hpp"

namespace protocol_ns {
    using namespace log_ns;

    // 设计的协议的报头和报文的格式
    // "len"\r\n"{json}"\r\n
    const std::string sep = "\r\n";
    const std::string space_sep = " ";

    // 给我们的报文加上报头
    std::string Encode(const std::string& jsonstring) {
        int len = jsonstring.size();
        if (len == 0) return "";
        return std::to_string(len) + sep + jsonstring + sep;
    }

    // 给我们的报文解密
    std::string Decode(std::string& jsonstring) {
        auto pos = jsonstring.find(sep);
        if (pos == std::string::npos) return "";
        // 现在开始截取json串
        std::string lenstr = jsonstring.substr(0, pos);
        int len = std::stoi(lenstr);
        if (jsonstring.size() < 2 * sep.size() + len + lenstr.size()) return "";

        size_t nextpos = jsonstring.find(sep, pos + sep.size());
        if (nextpos == std::string::npos) return "";
        std::string json = jsonstring.substr(pos + sep.size(), len);
        // 现在将jsonstring 给删除一部分
        jsonstring.erase(0, 2 * sep.size() + len + lenstr.size());
        return json;
    }

    class Request {
    public:
        Request() {}
        Request(int x, int y, char oper)
            : _x(x),
              _y(y),
              _oper(oper)
        {}

        // 序列化、反序列化
        std::string Serialize() {
#ifdef SELF
            Json::Value root;
            root["x"] = _x;
            root["y"] = _y;
            root["oper"] = _oper;
            
            Json::FastWriter writer;
            std::string s = writer.write(root);

            return s;
#else
            // x oper y 进行序列化
            std::string x_str = std::to_string(_x);
            std::string y_str = std::to_string(_y);
            // std::string oper_str = std::to_string(_oper);
            // return x_str + space_sep + oper_str + space_sep + y_str;
            std::string ret = x_str + space_sep;
            ret += _oper;
            return ret + space_sep + y_str;
#endif
        }

        void Deserialize(const std::string& info) {
#ifdef SELF
            Json::Reader reader;
            Json::Value root;

            bool parsingSuccessful = reader.parse(info, root);
            if (!parsingSuccessful) {
                LOG(FATAL, "fail to parse json\n");
                return;
            }

            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
#else
            // x oper y
            auto pos = info.find(space_sep);
            auto rpos = info.rfind(space_sep);
            _x = std::stoi(info.substr(0, pos));
            _oper = info[rpos - 1];
            _y = std::stoi(info.substr(rpos + space_sep.size()));
#endif        
        }

        int Get_X() {
            return _x;
        }

        int Get_Y() {
            return _y;
        }

        char Get_oper() {
            return _oper;
        }
        
        void SetValue(int x, int y, char oper) {
            _x = x;
            _y = y;
            _oper = oper;
        }

        ~Request() {}
    private:
        int _x;
        int _y;
        char _oper;
    };

    class Responce {
    public:
        Responce()
            : _result(0),
              _code(0),
              _desc("success") 
        {}

        std::string Serialize() {
#ifdef SELF
            Json::Value root;
            root["result"] = _result;
            root["code"] = _code;
            root["desc"] = _desc;

            Json::FastWriter writer;
            std::string s = writer.write(root);

            return s;
#else
            // result code desc
            std::string resultstr = std::to_string(_result);
            std::string codestr = std::to_string(_code);
            return resultstr + space_sep + codestr + space_sep + _desc;
#endif        
        }

        void Deserialize(const std::string& info) {
#ifdef SELF
            Json::Reader reader;
            Json::Value root;

            bool parsingSuccessful = reader.parse(info, root);
            if (!parsingSuccessful) {
                LOG(FATAL, "fail to parse json\n");
                return;
            }

            _result = root["result"].asInt();
            _code = root["code"].asInt();
            _desc = root["desc"].asString();
#else   
            // result code desc
            auto pos = info.find(space_sep), rpos = info.rfind(space_sep);
            _result = std::stoi(info.substr(0, pos));
            _code = std::stoi(info.substr(pos + space_sep.size(), rpos));
            _desc = info.substr(rpos + space_sep.size());
#endif
        }

        int& Get_result() {
            return _result;
        }

        int& Get_code() {
            return _code;
        }

        std::string& Get_desc() {
            return _desc;
        }

        void PrintResult() {
            std::cout << "result: " << _result << ", code: " << _code << ", desc:" << _desc << std::endl;

        }

        ~Responce() {}

    private:
        int _result;
        int _code; // 0:success  1:div zero  2.illegal
        std::string _desc;
    };

    class Factory {
    public:
        static std::shared_ptr<Request> BuildRequest() {
            return std::make_shared<Request>();
        }

        static std::shared_ptr<Responce> BuildResponce() {
            return std::make_shared<Responce>();
        }
    };
}


